#ifndef Class_First
#define Class_First
#ifdef __GNUG__
#pragma interface
#endif

#include "Object.h"

class OrdCollection;
class Collection;
class Iterator;

enum ClassFlags {
	eClassAbstract  =   BIT(eObjLast + 1),      // abstract class
	eClassObject    =   BIT(eObjLast + 2),      // ???
	eClassLast      =   eObjLast + 2
};

typedef (*classShowFunc)(char*, void*, int, bool);

//---- Class -------------------------------------------------------------------

class Class: public Object {

public:
	MetaDef(Class);
	Class(const char *name, int sz, Object *pro, const char *in,
		const char *dn, int il, int dl, bool abstract, double version);
	Class(const char *name, int sz, Class *super, Object *pro, const char *in, 
		const char *dn, int il, int dl, bool abstract, double version);
	Class(const char *name, int sz, const char *in, int il, classShowFunc f= 0);
	Class(const char *name, double vers);
	~Class();
	void Init(const char *name, int sz, Object *pro, const char *implfn,
			const char *declfn, int il, int dl, bool abstract, double vers);

	//---- attributes
	const char *Name() const;
	int Size() const;
	bool IsAbstract();
	Object *Proto() const;
	OrdCollection *SubClasses() const;
	double Version() const;
	void SetVersion(double);
	double LoadVersion() const;
	void SetLoadVersion(double);
		
	//---- class hierarchy
	Class *Super() const;
	Class *LoadSuper() const;
	void SetSuper();
	bool isKindOf(Class*);
	void AddSubclass(Class*);
	Iterator *SubclassIterator();

	//---- comparing
	u_long Hash();
	bool IsEqual(Object*);
	int Compare(Object*);

	//---- converting, input/output
	const char *AsString();
	void Show(char *buf, void *addr, int len, bool isptr);
	OStream &PrintOn(OStream&);
	Object *ReadAndMap(IStream&);

	//---- members
	Object *SomeMember();
	void EnumerateMembers(AccessMembers *accessor= 0);
	void EnumerateMyMembers(AccessMembers *accessor= 0);

	//---- methods
	Collection *GetMethods();
	void SetMethods(Collection*);

	//---- source access
	const char *GetDeclFileName();
	const char *GetImplFileName();
	int GetImplFileLine();
	int GetDeclFileLine();

	//---- instance statistics
	Object *SomeInstance();
	void AddInstance();
	int GetInstanceCount();
	void ResetInstanceCount();

protected:
	static Class *classptr;

	Class *super, *loadsuper;
	const char *className, *declFileName, *implFileName;
	Object *proto;
	double version, loadversion;
	int myId, size, declFileLine, implFileLine, instanceCount;
	OrdCollection *subclasses;
	Collection *methods;
	classShowFunc showfunc;
};

inline const char *Class::Name() const
	{ return className; }
inline int Class::Size() const
	{ return size; }
inline bool Class::IsAbstract()
	{ return TestFlag(eClassAbstract); }
inline Object *Class::Proto() const
	{ return proto; }
inline OrdCollection *Class::SubClasses() const
	{ return subclasses; }
inline double Class::Version() const
	{ return version; }
inline void Class::SetVersion(double v)
	{ version= v; }
inline double Class::LoadVersion() const
	{ return loadversion; }
inline void Class::SetLoadVersion(double v)
	{ loadversion= v; }
inline Class *Class::Super() const
	{ return super; }
inline Class *Class::LoadSuper() const
	{ return loadsuper; }
inline Collection *Class::GetMethods()
	{ return methods; }
inline void Class::SetMethods(Collection *col)
	{ methods= col; }
inline const char *Class::GetDeclFileName()
	{ return declFileName; }
inline const char *Class::GetImplFileName()
	{ return implFileName; }
inline int Class::GetImplFileLine()
	{ return implFileLine; }
inline int Class::GetDeclFileLine()
	{ return declFileLine; }
inline void Class::AddInstance()
	{ instanceCount++; }
inline int Class::GetInstanceCount()
	{ return instanceCount; }
inline void Class::ResetInstanceCount()
	{ instanceCount= 0; }

//---- SimpleMetaImpl macros ---------------------------------------------------

#define _SimpleMetaImpl(name,printname) \
	void _NAME2_(name,_Show)(char*, void*, int, bool); \
	static Class _NAME2_(name,ClassMetaImpl0)(_QUOTE_(printname), \
		sizeof(name),__FILE__, __LINE__, (classShowFunc)_NAME2_(name,_Show)); \
	Class *SMeta(name)= &_NAME2_(name,ClassMetaImpl0); \
	void _NAME2_(name,_Show)(char *buf, void *addr, int len, bool isptr)

#define SimpleMetaImpl(name) _SimpleMetaImpl(name,name)

//---- MetaImpl macros ---------------------------------------------------------

class _Object_dummy;

#define _MetaImplVers0(name,super,abstract,version) \
	static Class _NAME2_(name,ClassMetaImpl0)(_QUOTE_(name), sizeof(name), \
	new name((_Object_dummy*)0), \
	__FILE__, \
	_NAME2_(name,DeclFileName)(), \
	__LINE__, \
	_NAME2_(name,DeclFileLine)(), \
	abstract, \
	version); \
Class *name::isa= &_NAME2_(name,ClassMetaImpl0); \
name::name(_Object_dummy *d) : super(d) \
	{ _NAME2_(name,ClassMetaImpl0).SetSuper(); } \
Class *name::IsA() const \
	{ return &_NAME2_(name,ClassMetaImpl0); }

#define _MetaImpl0(name,super,abstract) \
	_MetaImplVers0(name,super,abstract,(double)0.0)

#define _NewMetaImplVers0(name,super,abstract,version) \
	static Class _NAME2_(name,ClassMetaImpl0)(_QUOTE_(name), \
	sizeof(name), \
	super::isa, \
	new name((_Object_dummy*)0), \
	__FILE__, \
	_NAME2_(name,DeclFileName)(), \
	__LINE__, \
	_NAME2_(name,DeclFileLine)(), \
	abstract, \
	version); \
Class *name::isa= &_NAME2_(name,ClassMetaImpl0); \
name::name(_Object_dummy *d) : super(d) \
	{ } \
Class *name::IsA() const \
	{ return &_NAME2_(name,ClassMetaImpl0); }

#define _NewMetaImpl0(name,super,abstract) \
	_NewMetaImplVers0(name,super,abstract,(double)0.0)

#define MetaImpl0(name) \
_MetaImpl0(name,,FALSE) \
void name::Members(AccessMembers *) { }

#define MetaImpl(name,list) \
_MetaImpl0(name,,FALSE) \
void name::Members(AccessMembers *ac) { _accessMembers= ac; ScanMembers list; }

#define AbstractMetaImpl0(name) \
_MetaImpl0(name,,TRUE) \
void name::Members(AccessMembers *) { }

#define AbstractMetaImpl(name,list) \
_MetaImpl0(name,,TRUE) \
void name::Members(AccessMembers *ac) { _accessMembers= ac; ScanMembers list; }


#define NewMetaImpl0(name,super) \
_NewMetaImpl0(name,super,FALSE) \
void name::Members(AccessMembers *) { }

#define NewMetaImplVersion0(name,super,version) \
_NewMetaImplVers0(name,super,FALSE,version) \
void name::Members(AccessMembers *) { }

#define NewMetaImpl(name,super,list) \
_NewMetaImpl0(name,super,FALSE) \
void name::Members(AccessMembers *ac) { _accessMembers= ac; ScanMembers list; }

#define NewMetaImplVersion(name,super,list,version) \
_NewMetaImplVers0(name,super,FALSE,version) \
void name::Members(AccessMembers *ac) { _accessMembers= ac; ScanMembers list; }

#define NewAbstractMetaImpl0(name,super) \
_NewMetaImpl0(name,super,TRUE) \
void name::Members(AccessMembers *) { }

#define NewAbstractMetaImplVersion0(name,super,version) \
_NewMetaImplVers0(name,super,TRUE) \
void name::Members(AccessMembers *) { }

#define NewAbstractMetaImpl(name,super,list) \
_NewMetaImpl0(name,super,TRUE) \
void name::Members(AccessMembers *ac) { _accessMembers= ac; ScanMembers list; }

#define NewAbstractMetaImplVersion(name,super,list,version) \
_NewMetaImplVers0(name,super,TRUE,version) \
void name::Members(AccessMembers *ac) { _accessMembers= ac; ScanMembers list; }

//---- type specifiers for metaclass macros ------------------------------------

#define T_SIM       1
#define T_PTR       2
#define T_VEC       4
#define T_ARR       8
#define T_STR       16
#define T_PTR2      32

#define _offset(in) (u_long)&in
#define _aoffset(in) (u_long)in
#define _TO(x) _Type(TYPEOF(x))

#define TC(in,cast) (_an++,T_SIM), _QUOTE_(in), _Type((cast*)&in), _offset(in)

#define T(in) (_an++,T_SIM), _QUOTE_(in), _Type(&in), _offset(in)

#define TP(in) (_an++,T_PTR), _QUOTE_(in), _Type(in), _offset(in)
#define TS(in) (_an++,T_STR), _QUOTE_(in), _Type(in), _offset(in)
#define TA(in) (_an++,T_ARR), _QUOTE_(in), _Type(in), _aoffset(in), sizeof(in)/sizeof(*in)
#define TV(in,len) (_an++,T_VEC), _QUOTE_(in), _Type(in), _offset(in), _offset(len)

#define TPP(in) (_an++,T_PTR+T_PTR2), _QUOTE_(in), _TO(in), _offset(in)
#define TSP(in) (_an++,T_STR+T_PTR2), _QUOTE_(in), _TO(in), _offset(in)
#define TAP(in) (_an++,T_ARR+T_PTR2), _QUOTE_(in), _TO(in), _aoffset(in), sizeof(in)/sizeof(*in)
#define TVP(in,len) (_an++,T_VEC+T_PTR2), _QUOTE_(in), _TO(in), _offset(in), _offset(len)

//---- meta casses for builtin types ------------------------------------------

SimpleMetaDef(char);
SimpleMetaDef(int);
SimpleMetaDef(short);
SimpleMetaDef(long);
SimpleMetaDef(float);
SimpleMetaDef(double);
SimpleMetaDef(byte);
SimpleMetaDef(u_short);
SimpleMetaDef(u_int);
SimpleMetaDef(u_long);

// dummy classes for formatting booleans and flags

class _flags { };
class _bool { };
class _enum { };

SimpleMetaDef(_flags);
SimpleMetaDef(_bool);
SimpleMetaDef(_enum);

#define TX(in) TC(in,_flags)
#define TB(in) TC(in,_bool)
#define TE(in) TC(in,_enum)

#endif
